package https

import (
	"encoding/json"
	"fmt"
	"strconv"
	"strings"
	"time"
)

// 返回值中的字符串替换
// 此功能会替换 body 内容，请在 GET / POST 之后再行替换
//
//	old	待替换内容
//	new	替换成
func (curl *CURL) Replace(old, new string) *CURL {
	if old == "" {
		return curl
	}
	curl.Body = strings.ReplaceAll(curl.Body, old, new)
	return curl
}

// 获取JSON中的数据
//
//	obj			要获取的obj对象，需要提供给json.Unmarshal
//	first...	simplejson.GetPath传入的string列表
func (curl *CURL) Json(obj any, first ...string) error {
	if curl.Error != nil {
		return curl.Error
	}
	if curl.HttpCode == 0 && len(curl.Body) == 0 {
		// 该请求还未进行最终的GET/POST请求，所以此处直接默认为GET请求
		curl.Get()
		if curl.Error != nil {
			return curl.Error
		}
	}
	// 如果传入nil则表示舍弃该值
	if obj == nil {
		return nil
	}
	if len(first) == 0 {
		curl.OverTime = time.Now()
		return json.Unmarshal([]byte(curl.Body), obj)
	}
	ot, err := QueryJsonString([]byte(curl.Body), first...)
	if err != nil {
		return err
	}
	err = json.Unmarshal(ot, obj)
	curl.OverTime = time.Now()
	return err
}

// 获取JSON中的Data对象
//
//	obj	要转化的对象，需要在json中的data里面
func (curl *CURL) JsonData(obj any) error {
	return curl.Json(obj, "data")
}

// 将结果返回的JSON字符串进行转化、提取成指定路径的JSON字符串
//
//	outs	待截取的JSON字符串
//	path	截取下标，如果是列表类型的话，需要拼成字符串类型再行读取，如"0"、"1"等
func QueryJsonString(outs []byte, path ...string) ([]byte, error) {
	if len(path) == 0 {
		return outs, nil
	}
	var data any
	err := json.Unmarshal(outs, &data)
	if err != nil {
		return outs, fmt.Errorf("抱歉，该字符串解析失败，请先确认JSON是否完整: %w", err)
	}
	for _, p := range path {
		switch v := data.(type) {
		case map[string]any:
			var ok bool
			data, ok = v[p]
			if !ok {
				return outs, fmt.Errorf("该下标未找到：%s", p)
			}
		case []any:
			ind, err := strconv.Atoi(p)
			if err != nil {
				return outs, fmt.Errorf("抱歉，该下标 %s 无法转换成整数数字，请确认后再次尝试: %w", p, err)
			}
			if len(v) <= ind {
				return outs, fmt.Errorf("该下标超出数据的长度限制: 最大长度：%d, 读取下标：%d", len(v), ind)
			}
			data = v[ind]
		default:
			return outs, fmt.Errorf("无法解析的数据类型")
		}
	}
	return json.Marshal(data)
}
